package com.gitee.wsl.ext.number

import kotlin.math.abs
import kotlin.math.floor
import kotlin.math.log10
import kotlin.math.pow
import kotlin.math.sqrt


fun ClosedRange<Float>.tickStep(count: Int) = tickIncrement(start,endInclusive,count)

@JvmName("tickStepDouble")
fun ClosedRange<Double>.tickStep(count: Int) = tickIncrement(start,endInclusive,count)


/** See equivalent [d3 function](https://github.com/d3/d3-array#tickStep). */
fun tickStep(start: Float, stop: Float, count: Int): Float =
    tickStep(start.toDouble(), stop.toDouble(), count).toFloat()

/** See equivalent [d3 function](https://github.com/d3/d3-array#tickStep). */
fun tickStep(start: Double, stop: Double, count: Int): Double {
    require(count > 0) { "Count must be positive, but was $count." }
    if (start == stop) return 0.0
    val preciseStep = abs(stop - start) / count
    val roundedStep = (10.0).pow(floor(log10(preciseStep)))
    val error = preciseStep / roundedStep
    val finalStep = errorScaleOf(error) * roundedStep
    return if (start < stop) finalStep else -finalStep
}

internal fun errorScaleOf(error: Double): Int = when {
    error >= sqrt50 -> 10
    error >= sqrt10 -> 5
    error >= sqrt2 -> 2
    else -> 1
}

private val sqrt50 = sqrt(50.0)
private val sqrt10 = sqrt(10.0)
private val sqrt2 = sqrt(2.0)